#define _GNU_SOURCE

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<stdbool.h>
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<pwd.h>
#include<grp.h>
#include<time.h>
#include<pthread.h>

#include "exe5.h"

//Ubuntu上的stat.h中提供的宏定义为ISLNK
#ifndef S_ISLINK
#define S_ISLINK S_ISLNK
#endif

#define BUFSIZE 16384
#define USER_MODE(st, code) (code&st)==code

int get_file_list(DIR *dir, char** file_list, bool show_self, bool show_parent, bool show_hide){
    struct dirent* file;
    char *name;
    int i=0;
    while((file = readdir(dir)) != NULL){
        name = file->d_name;
        //跳过自己
        if(!show_self && strcmp(name,".")==0)
            continue;
        //跳过父文件夹
        if(!show_parent && strcmp(name,"..")==0)
            continue;
        //跳过隐藏文件
        if(!show_hide && file->d_reclen>1 && name[0] == '.' && strcmp(name,"..")!=0 && strcmp(name,".")!=0)
            continue;
        file_list[i++] = file->d_name;
    }
    return i;
}

void *cp(void *arg){
    struct CP_args * args=(struct CP_args *)arg;
    
    FILE *source, *target;
    int i;
    source = fopen(args->file_path, "rb"); 

    if( source == NULL ) { printf("Press any key to exit...\n");} //exit(EXIT_FAILURE); 

    fseek(source, 0, SEEK_END);
    int length = ftell(source);

    fseek(source, 0, SEEK_SET);
    target = fopen(args->obj_path, "wb"); 

    if( target == NULL ) { fclose(source); } //exit(EXIT_FAILURE);

    for(i = 0; i < length; i++){
        fputc(fgetc(source), target);
    }
    fclose(source); 
    fclose(target);
    
    printf("copy %s to %s successful!\n", args->file_path, args->obj_path);
	return (void *)0;
}

void *ls_cp(void *arg){
    struct LSCP_args * args=(struct LSCP_args *)arg;

    DIR* dir = opendir(args->src_dir);
    if(dir==NULL){
        fprintf(stderr, "open directory fail\n");
        return (void *)-1;
    }

    //读取目录文件列表
    int file_list_size;
    char* file_list[1024];

    file_list_size = get_file_list(dir, file_list, false, false, true);


    struct stat file_stat;
    char* file_path=(char*)malloc(sizeof(char)*512);
    
    for(int i=0;i<file_list_size;i++){
        sprintf(file_path,"%s/%s",args->src_dir,file_list[i]);
        if (stat(file_path,&file_stat)==0){
            if(file_stat.st_mode & S_IFDIR){
                //目录
                printf("%s is a directory.\n",file_path);
                struct LSCP_args lscp_args;
                lscp_args.src_dir=(char*)malloc(sizeof(char)*512);
                lscp_args.obj_dir=(char*)malloc(sizeof(char)*512);

                lscp_args.obj_dir=args->obj_dir;
                sprintf(lscp_args.src_dir,"%s",file_path);
                
                pthread_t tid;
                if(pthread_create(&tid,NULL,(void *) ls_cp,(void *)&lscp_args)!=0){
                    printf("thread %s creation faild!\n",file_list[i]);
                }
                pthread_join(tid,NULL);
            }else if (file_stat.st_mode & S_IFREG){
                //文件,创建线程复制
                struct CP_args cp_args;
                cp_args.file_path=(char*)malloc(sizeof(char)*512);
                cp_args.obj_path=(char*)malloc(sizeof(char)*512);

                sprintf(cp_args.file_path,"%s",file_path);
                sprintf(cp_args.obj_path,"%s/%s",args->obj_dir,file_list[i]);

                pthread_t tid;
                if(pthread_create(&tid,NULL,(void *) cp,(void *)&cp_args)!=0){
                    printf("thread %s creation faild!\n",file_list[i]);
                }
                pthread_join(tid,NULL);
            }else{
                printf("%s is either file or directory \n",file_list[i]);
            }
            }else{
                printf("error, %s doesn't exist \n",file_list[i]);
            }
    }
    if(closedir(dir)==-1){
        printf("close dir fail\n");
        exit(-1);
    }
    return (void *)0;

}


int main(int argc,char** argv){

    struct LSCP_args lscp_args;
    lscp_args.src_dir=(char*)malloc(sizeof(char)*512);
    lscp_args.obj_dir=(char*)malloc(sizeof(char)*512);

    sprintf(lscp_args.src_dir,"%s/source_dir",get_current_dir_name());
    sprintf(lscp_args.obj_dir,"%s/object_dir",get_current_dir_name());

    pthread_t tid;
    pthread_create(&tid,NULL,(void *) ls_cp,(void *)&lscp_args);
    pthread_join(tid,NULL);
    return 0;
}